

#include "countmin.h"

static int free_Integer_table(st__table * table);
static Integer *My_ddCountMintermAux(DdManager * manager, DdNode * node, Integer *  max, st__table * table, int nsize);
static double Integer_Error(Integer *value,int nVars);

static DdNode *background,*zero;

//同时判断是否满足约束和计算错误率
extern int ErrorRate(Abc_Ntk_t *pNtk, Integer *Bound, double *rrate)
{
	int flag = -1;
	Abc_Obj_t *CO1 = NULL;
	DdNode * bFunc = NULL;
	DdManager * dd = NULL;
	dd = pNtk->pManFunc;

	CO1 =  Abc_ObjFanin0(Abc_NtkCo(pNtk,0));
	bFunc = CO1->pData;
	
	Integer * res = Cudd_CountMinterm_Large(dd, bFunc, Cudd_ReadSize(dd));
	//Print_Integer(res);
	if(Bound != NULL) {
		if(Integer_Compare(res, Bound) == 1) {
			flag = 0;
		}
		else {
			flag = 1;
		}
	}
	double rate = Integer_Error(res,Cudd_ReadSize(dd));
	*rrate = rate;
	Integer_Free(res);
	return flag;
}

//本函数是用来计算错误率，通过BDD计算最小项

//错误率是否满足约束
extern int ErrorMinterm(Abc_Ntk_t *pNtk, Integer *Bound)
{
	int flag = 0;
	Abc_Obj_t *CO1 = NULL;
	DdNode * bFunc = NULL;
	DdManager * dd = NULL;
	dd = pNtk->pManFunc;

	CO1 =  Abc_ObjFanin0(Abc_NtkCo(pNtk,0));
	bFunc = CO1->pData;
	
	Integer * res = Cudd_CountMinterm_Large(dd, bFunc, Cudd_ReadSize(dd));
	if(Integer_Compare(res, Bound) == 1) {
	 	flag = 0;
	}
	else {
		flag = 1;
	}
	
	Integer_Free(res);
	return flag;
}
//将两个电路输出分别异或之后再或
extern double Print_ErrorRate(Abc_Ntk_t *pNtk)
{
	DdManager * dd = NULL;
	Abc_Obj_t *CO1 = NULL;
	DdNode * bFunc = NULL;

	dd = pNtk->pManFunc;
	CO1 =  Abc_ObjFanin0(Abc_NtkCo(pNtk,0));
	bFunc = CO1->pData;
	
	Integer * res = Cudd_CountMinterm_Large(dd, bFunc, Cudd_ReadSize(dd));
	//printf("错误输入组合：");
	//Print_Integer(res);
	
	//Print_BddNodeNumber(dd);
	//printf("错误输入组合：%lld \n",(long long)Cudd_CountMinterm(dd, bFunc, Cudd_ReadSize(dd)));
	double aaa = Integer_Error(res,Cudd_ReadSize(dd));
	Integer_Free(res);
	return aaa;
}

//错误率计算
static double Integer_Error(Integer *value,int nVars)
{
	int len = 0;
	double tmp1 = 0;
	len = value->length;
	if(nVars <= 13) {
		tmp1 = ((double)value->vec[0])/(0x01<<nVars);
		return tmp1;
	}
	Integer_Shift(value,value,1,nVars - 13);
	return (value->vec[0]*1.0)/(0x01<<13);
}

static Integer *
My_ddCountMintermAux(
  DdManager * manager,
  DdNode * node,
  Integer *  max,
  st__table * table,
  int nsize)
{
    DdNode      *N, *Nt, *Ne;
    Integer     *min=NULL, *minT=NULL, *minE=NULL,*max_new=NULL;
    DdNode      *res;
	int co = 0;
	
    N = Cudd_Regular(node);
    if (cuddIsConstant(N)) {
        if (node == background || node == zero) {
            return(Integer_Init_fast(max->length,max->size));
        } else {
			Integer_Dup(max,&max_new);
            return(max_new);
        }
    }
	
	if (N->ref != 1 && (st__lookup(table, (const char *)node, (char **)&min) != 0)) {
        return(min);
    }

    Nt = cuddT(N); Ne = cuddE(N);
    if (Cudd_IsComplement(node)) {
        Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne);
    }
	
    minT = My_ddCountMintermAux(manager,Nt,max,table,nsize);
    if (minT == (Integer *)CUDD_OUT_OF_MEM) return((Integer *)CUDD_OUT_OF_MEM);
	//Integer_Shift(minT,minT,1,1);
    minE = My_ddCountMintermAux(manager,Ne,max,table,nsize);
    if (minE == (Integer *)CUDD_OUT_OF_MEM) return((Integer *)CUDD_OUT_OF_MEM);
	//Integer_Shift(minE,minE,1,1);
	min = Integer_Init_fast(max->length,max->size);
	Integer_Add(minT,minE,min,&co);
	Integer_Shift(min,min,1,1);
	if (N->ref != 1) {
		if (st__insert(table, (char *)node, (char *)min) == st__OUT_OF_MEM) {
			Integer_Free(min);
			return((Integer *)CUDD_OUT_OF_MEM);
		}
	}
	if(Cudd_Regular(Nt)->ref == 1) {
		Integer_Free(minT);
	}
	if(Cudd_Regular(Ne)->ref == 1) {
		Integer_Free(minE);
	}

    return(min);

} /* end of ddCountMintermAux */


extern Integer *
Cudd_CountMinterm_Large(
  DdManager * manager,
  DdNode * node,
  int  nvars)
{
	
    
    Integer *     max = Integer_Init(nvars);
    st__table *table;
    Integer *     res = NULL,*res_new = NULL;
    CUDD_VALUE_TYPE epsilon;

    background = manager->background;
    zero = Cudd_Not(manager->one);

	//计算2^nvars
	Integer_SetOne(max);
	Integer_Shift(max,max,0,nvars);

	table = st__init_table( st__ptrcmp, st__ptrhash);
    if (table == NULL) {
        return((Integer *)CUDD_OUT_OF_MEM);
    }
	
    //epsilon = Cudd_ReadEpsilon(manager);
    //Cudd_SetEpsilon(manager,(CUDD_VALUE_TYPE)0.0);
    res = My_ddCountMintermAux(manager,node,max,table,nvars);
	Integer_Dup(res,&res_new);
	
	if(Cudd_Regular(node)->ref == 1) {
		Integer_Free(res);
	}
	free_Integer_table(table);
	Integer_Free(max);
	
	st__free_table(table);
    //Cudd_SetEpsilon(manager,epsilon);
	//printf("%lf \n",Cudd_CountMinterm(manager, node, Cudd_ReadSize(manager)));
    return(res_new);

} /* end of Cudd_CountMinterm */

static int free_Integer_table(st__table * table)
{
	st__generator * gen = NULL;
	DdNode *key_p = NULL;
	Integer *value_p = NULL;
	gen = st__init_gen(table);
	while(st__gen(gen, (const char **)&key_p, (char**)&value_p) != 0) {
		Integer_Free(value_p);
	}
	st__free_gen(gen);
	return 0;
}


